home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 016a / del10.zip / DEL!.ASM next >
Assembly Source File  |  1991-12-08  |  15KB  |  601 lines

  1.     PAGE    60,132
  2.     TITLE    DEL! replacement for DOS DEL command
  3. Comment |
  4.  
  5. ┌─────────────────────┐
  6. │ DEL! C:\MySub\X.Txt │
  7. │ DEL! C:\MySub\X?.*  │
  8. │ DEL! C:MySub\*.*    │
  9. │ DEL! X.TXT          │
  10. │     ^watch the space│
  11. └─────────────────────┘
  12.  
  13. Written in Microsoft Assembler MASM 5.0, MASM 6.0 and OPTASM 1.61b
  14.  
  15. written 1991 December 7
  16.  
  17. by Roedy Green
  18. Canadian Mind Products
  19. #168 - 1020 Mainland Street
  20. Vancouver, BC
  21. Canada    V6B 2T4
  22. (604) 684-6529
  23.  
  24. This program is copyrighted but free.  The source and object
  25. code may be used for any purpose except military.  You are free
  26. to copy it, sell it, modify it, or cannibalize it.  You may even
  27. take out the credits if you want.  The only restriction is
  28. that you must make sure none of it is ever used for a military
  29. purpose.
  30.  
  31. Version History:
  32. ****************
  33.  
  34. Version 1.0  1991/12/07  released to BIX
  35. This is the initial version.
  36.  
  37.  
  38. Purpose
  39. *******
  40.  
  41. DEL! is very similar to the normal MS or PC DOS DEL command,
  42. however DEL! is somewhat more powerful.
  43.  
  44. DEL! is just a heavy duty form of DEL for use in BAT files such
  45. as installs.  Its personality is roughly modeled on Arnold's
  46. Schwartzenegger's character in Terminator III.
  47.  
  48. DEL! is taciturn.  It does not complain if the file has already
  49. been deleted -- no more:
  50.     IF EXIST X.TXT DEL X.TXT
  51. just
  52.     DEL! X.TXT
  53.  
  54. DEL! never generates an error message, even when it can find no
  55. files to delete.  If you give it the name of a subdirectory
  56. (without *.*) to delete it does nothing, and makes no complaint.
  57. However if it cannot delete any files, it sets errorlevel to 1.
  58.  
  59. DEL! is ruthless.  It does not pause for confirmation on DEL! *.*
  60. No more SAY! "Y" 13 | DEL *.* >NUL
  61. just    DEL! *.*
  62.  
  63. DEL! is tough.    It also deletes hidden and read-only files.
  64.  
  65. DEL! is respectful of authority. It will NOT delete system files.
  66.  
  67. DEL! is light on its feet.  It is only 385 bytes.
  68.  
  69. DEL! is slower than DEL since it is must be loaded each time,
  70. whereas DEL is internal to DOS.
  71.  
  72.  
  73. Tools
  74. *****
  75.  
  76. DOS offers a set of awkward tools for this job:
  77.  
  78. ----
  79.  
  80. We can use the old FCB style delete.
  81.  
  82. AH       13h
  83. DS:DX       Pointer to an unopened FCB
  84. returns:
  85. AL       00h         If file deleted
  86.        FFh         If file not found
  87.  
  88. The catches are:
  89. Only works on the current directory.
  90. Does not work on hidden or read-only files.
  91. Only allows ? as a wild card, not *
  92.  
  93. ----
  94.  
  95. We can use the Handle style UNLINK delete
  96.  
  97. AH       41h
  98. DS:DX       Pointer to filespec (ASCIIZ string)
  99. returns;
  100. AX       Error code, if CF is set
  101. 2       File not found
  102. 3       Path not found
  103. 5       Access denied
  104.  
  105. The catches are:
  106. Does not allow any wildcards.
  107. Does not work on read-only files.
  108.  
  109. ----
  110.  
  111. To make read-only files deletable, we can change their attributes
  112.  
  113.  AH        43h
  114.  AL        01h
  115.  CX        Desired attributes
  116.  DS:DX        Pointer to filespec (ASCIIZ string)
  117. returns:
  118.  AX        Error code, if CF is set
  119.  
  120. The catches are:
  121. Does not allow any wildcards.
  122.  
  123. ----
  124.  
  125. To search with general wildcards: find first:
  126.  
  127.  AH        4Eh
  128.  CX        File attribute
  129.  DS:DX        Pointer to filespec (ASCIIZ string)
  130. returns
  131.  AX        Error code, if CF is set
  132.  2        File not found
  133.  3        Path not found
  134.  18        No more files to be found
  135.  
  136. Find next
  137.  AH        4Fh
  138. returns
  139.  AX        Error code, if CF is set
  140.  
  141.  18        No more files to be found
  142.  
  143. the DTA looks like this:
  144. Offset       Size       Description
  145.  00h        21          Used by DOS for find-next processing
  146.  15h         1          Attribute of file found
  147.  16h         2          Time stamp of file
  148.  18h         2          Date stamp of file
  149.  1Ah         4          File size in bytes
  150.  1Eh        13          Filename and extension, as an ASCIIZ string
  151.               e.g.  X.TXT_ <-null
  152.  
  153.  
  154.  
  155. Notes an How DEL! Works
  156. ***********************
  157.  
  158. DEL! parses the command line looking for a file or wildcard
  159. name.
  160.  
  161. Initialize the errorlevel to 1, presume failure.
  162.  
  163. We do a find first (function 4E) with hidden, read-only etc
  164. attributes turned on so we see those files too.  We don't peek
  165. at subdirs or system files. We feed it the ENTIRE filename --
  166. including any wildcards and filename.
  167.  
  168. If there were no files we quit.
  169.  
  170. We split out the drive:directory part of the name with
  171. possible trailing \, with wildcards or filename stripped off.
  172. e.g. C:\MYSUB\ C:\ C: \MYSUB\ MYSUB\SUB2\  null
  173. In other words, all ready to glue on the filename.
  174.  
  175. AGAIN:
  176.  
  177. DOS gives us just the filename and extension, not the drive or
  178. directory. Compose its fullname by concatenating the filename
  179. onto the end of the drive/dirname.
  180.  
  181. If it is a read-only file we remove read-only status with
  182. function 43h.
  183.  
  184. Then we delete it with delete it with function 41h.
  185. If we were successful deleting, change the errorlevel to 0
  186.  
  187. We then continue with a FIND NEXT 4F
  188.  
  189. If there were no more files we quit.  If there was another, we
  190. loop back to AGAIN.
  191.  
  192. Future Improvements
  193. *******************
  194.  
  195. This program currently does THREE DOS function calls to get rid
  196. of each file:
  197.  
  198. 1. find next
  199. 2. fix attribute (for read only)
  200. 3. delete file
  201.  
  202. DOS ends up SEARCHING for the file to delete FROM SCRATCH!
  203.  
  204. What would be more efficient is to use the FCB-type delete,
  205. which can wipe out all the files in one DOS call.  The catch is
  206. you still have to use the current method to clean up afterwards
  207. since the FCB method cannot deal with hidden or read-only files.
  208.  
  209. The FCB speed up works like this:
  210.  
  211. Figure out which drive we are working with.
  212.  
  213. Get the current diretory on that drive and save it away.
  214.  
  215. Change the directory to the one where the files are we want to
  216. kill.  If there is no such directory, give up.
  217.  
  218. Peel off he wildcard tail from the command line and give that to
  219. the FCB delete.
  220.  
  221. Then continue with the handle method to get rid of any hidden or
  222. read-only files.
  223.  
  224.  
  225. | ; End of long comment
  226.  
  227. stack    segment stack        ; keep MS link happy by providing null stack
  228. stack    ends
  229.  
  230. ;==============================================================
  231.  
  232. CODE    SEGMENT PARA        ; start off in code.
  233.  
  234. ;==============================================================
  235.  
  236. data    segment word        ; provide a separate DATA segment
  237.                 ; Even though it appears in the source
  238.                 ; before the code, it the COM file it
  239.                 ; will appear at the end.  This is as dodge
  240.                 ; to avoid forward references that confuse
  241.                 ; MASM.
  242.  
  243. FirstData    Label    Word
  244.  
  245. data    endS
  246.  
  247. ;==============================================================
  248.  
  249. com    group    code,data
  250.  
  251.     ASSUME    CS:COM,DS:COM,ES:COM
  252.     ORG    100H
  253. Start:
  254.  
  255. ;==============================================================
  256.  
  257. ;    REGISTER CONVENTIONS
  258. ;    all registers are trashable in calls except BX CX and DI
  259. ;    BX often points to the start of part of the command string.
  260. ;    CX often counts number of chars in part of the command string.
  261. ;    DI often points to the last char of some part of the command string.
  262. ;    Because this is a com file, all segment registers are
  263. ;    stable equal to CS:
  264. ;======================================
  265.  
  266. Data    Segment
  267.  
  268.     EVEN
  269. DTA    LABEL    BYTE        ; disk transfer area
  270.                 ; Used in Find First Match
  271.     DB    21 DUP (0)    ; reserved for DOS
  272. Fattrib DB    0        ; attribute byte
  273. FTime    DW    0        ; file Time in directory form
  274. FDate    DW    0        ; file Date in directory form
  275. FSize    DW    0        ; 32 bit file size
  276.     DW    0
  277. FName    DB    13 DUP(0)    ; ASCIIZ file name and extension
  278.                 ; NOT parsed into fixed length file+ext
  279.                 ; NOTE DOS WILL NOT TELL US THE DIR NAME
  280.                 ; OR DRIVE.
  281.  
  282. DirStart    DW    0    ; addr where directory name starts
  283. DirTack     DW    0    ; addr byte just after dirname, wher
  284.                 ; we can tack on a filename.
  285.  
  286.                 ; Note we build pick out the filename
  287.                 ; as a subset of the command line.
  288.  
  289.                 ; We pick out he dirname as a subset
  290.                 ; of the filename in the command line.
  291.  
  292.                 ; We build the complete filenames in
  293.                 ; the command line too!
  294.  
  295.                 ; We don't need any string variables at all!
  296.  
  297. Errorlevel    DB    1    ; DOS exit code.  Presume failure.
  298.  
  299.  
  300.                 ; banner never displayed, but embedded in file.=
  301.  
  302. BannerMsg    DB '░▒▓█ DEL! 1.0 █▓▒░',13,10
  303.         DB 13,10
  304.         DB 'Copyright 1991 Roedy Green Canadian Mind Products',13,10
  305.         DB 'May be freely copied and used for any purpose but military.',13,10,'$'
  306.  
  307. Data    EndS
  308.  
  309. ;======================================
  310.  
  311. MAIN    PROC
  312.  
  313.     call    Parse        ; parse command line
  314.                 ; DS:BX len CX contains ASCIIZ string
  315.                 ; stripped of lead/trail blanks
  316.                 ; gets drive:dir\filename
  317.  
  318.  
  319.     Call    FindFirst    ; find first file that matches wildcard
  320.                 ; spec, or perhaps a perfect match.
  321.  
  322.     jc    Done        ; if no files, we are done
  323.  
  324.     Call    GetDirName    ; strip off the filename/wildcard
  325.                 ; leaving just the drive:directory
  326.  
  327. NextFile:
  328.     Call    BuildFilename    ; glue filename onto tag end of dirname.
  329.                 ; leave asciiz in DS:bx
  330.  
  331.     Call    RidRO        ; Get rid of the file, even if it was
  332.                 ; read-only.
  333.  
  334.     Call    FindNext    ; find next file matching wildcards
  335.  
  336.     Jnc    NextFile
  337. Done:
  338.     mov    ah,04Ch
  339.     mov    al,errorlevel    ; quit with 0 errorlevel if killed at least
  340.                 ; one file, 1 otherwise
  341.     int    21h        ; exit to DOS
  342.  
  343. MAIN    ENDP
  344.  
  345. ;======================================
  346.  
  347. Parse    PROC    NEAR
  348.  
  349. ;    Parse the command line to remove lead/trail blanks
  350. ;    and terminate by 2 nulls.
  351. ;    sample inputs
  352. ;    DEL!    C:\MySub\X.TXT
  353. ;    DEL! MySub2
  354. ;    DEL!
  355. ;    DEL!  D:\
  356. ;    DEL!  D:
  357. ;
  358. ;    When Done DS:BX points to start of string.
  359. ;    String will be terminated by 2 nulls
  360. ;    CX counts bytes in string exclusive of nulls
  361.                 ; counted string at HEX 80 PSP
  362.                 ; contains command line.
  363.                 ; Preceeded by unwanted spaces.
  364.                 ; possibly followed by unwanted spaces.
  365.                 ; currently missing a trailing null.
  366.     xor    ch,ch
  367.     mov    cl,ds:80h
  368.     mov    bx,81H
  369.     call    Mleading    ; get rid of leading blanks
  370.     call    MTrailing    ; get rid of trailing blanks
  371.     mov    di,bx        ; calc addr of byte just past end
  372.     add    di,cx
  373.     mov    word ptr [di],0 ; plop in pair of nulls after string
  374.     ret
  375.  
  376. Parse    ENDP
  377.  
  378. ;=======================================
  379.  
  380.  
  381. MLeading    PROC    Near
  382. ;    on entry BX is addr of string, CX its length
  383. ;    trims off any leading blanks, leaving result in BX CX
  384. ;    length may also be 0 or 1, but not -ve
  385. ;    If the entire string is blank the result is the null string
  386.     mov    di,bx
  387.     mov    al,20h        ; AL = blank  -- the search char
  388.     jcxz    mleading2    ; jump if null string
  389.     repe    scasb        ; scan ES:DI forwards till hit non blank
  390.                 ; DI points just after it (wrap ok)
  391.                 ; CX is one too small, or 0 if none found
  392.     je    mleading1    ; jump if entire string was blank
  393.     inc    cx        ; CX is length of remainder of string
  394. mleading1:
  395.     dec    di        ; DI points to non-blank
  396. mleading2:
  397.     mov    bx,di        ;a put address back
  398.     ret
  399. MLeading    ENDP
  400.  
  401. ;========================================
  402.  
  403. MTrailing    PROC    Near
  404. ;    on entry BX is addr of string, CX its length
  405. ;    trims off any trailing blanks, leaving result in BX CX
  406. ;    length may also be 0 or 1, but not -ve
  407. ;    If the entire string is blank the result is the null string
  408.     mov    di,bx
  409.     add    di,cx        ; calc addr last char in string
  410.     dec    di
  411.     mov    al,20h        ; AL = blank  -- the search char
  412.     jcxz    mtrailing1    ; jump if null string
  413.     std
  414.     repe    scasb        ; scan ES:DI backwards till hit non blank
  415.                 ; DI points just ahead of it (wrap ok)
  416.                 ; CX is one too small, or 0 if none found
  417.     cld
  418.     je    mtrailing1    ; jump if whole string was blank
  419.     inc    cx
  420. mtrailing1:
  421.     ret
  422. MTrailing    ENDP
  423.  
  424. ;========================================;====
  425.  
  426. FindFirst    Proc
  427.  
  428. ;    Find first file that matches our wildcard spec
  429. ;    on input DS:bx length cx is the filename.
  430. ;    preserves DS:bx cx
  431.  
  432.     push    bx
  433.     push    cx
  434.  
  435.     lea    dx,DTA
  436.     mov    ah,1Ah        ; set up DTA for DOS to report its findings
  437.     int    21h
  438.  
  439.     mov    dx,bx
  440.     mov    cx,03h        ; find read only and hidden files
  441.                 ; 01 bit 0 = RO      √
  442.                 ; 02 bit 1 = hidden  √
  443.                 ; 04 bit 2 = system
  444.                 ; 08 bit 3 = volume label
  445.                 ; 10 bit 4 = subdir
  446.                 ; 20 bit 5 = archive
  447.     mov    ah,4Eh
  448.     int    21h        ; find first
  449.                 ; STC notes trouble
  450.                 ; DTA contains results
  451.     pop    cx
  452.     pop    bx
  453.     ret
  454.  
  455. FindFirst    EndP
  456.  
  457. ;=======================================
  458.  
  459. GetDirName    PROC    Near
  460.  
  461. ;    on input DS:BX length CX points to filename on command line
  462. ;    We want to strip it back to drive:dirname
  463.  
  464.     mov    DirStart,bx    ; save pointer to the C:
  465.  
  466.     call    StripDrive    ; peel off the leading C:
  467.                 ; remainder is DS:bx len cx
  468.  
  469.     call    StripFile    ; peel off the trailing X.TXT *.* etc.
  470.                 ; remainder is DS:bx len cx, last di
  471.  
  472.                 ; di points to last char of string
  473.     inc    di        ; point just past end where can tack on.
  474.     mov    DirTack,di
  475.     ret
  476.  
  477. GetDirName    ENDP
  478.  
  479. ;=======================================
  480.  
  481.  
  482. StripDrive    PROC    Near
  483.  
  484. ;    Remove leading drive C: if any
  485. ;    XXX.TXT         ->  XXX.TXT
  486. ;    C:            ->  null
  487. ;    C:\            ->  \
  488. ;    C:\SUB1\SUB2\X.XX    ->  \SUB1\SUB2\X.X
  489. ;    ^ ^        ^
  490. ;    a b        c
  491. ;    input    DS:BX=a CX=length a..c
  492. ;    results DS:BX=b CX=length b..c
  493.  
  494.     cmp    byte ptr [bx+1],':'
  495.     jne    HasNoDrive
  496.     add    bx,2
  497.     sub    cx,2
  498. HasNoDrive:
  499.     ret
  500.  
  501. StripDrive    ENDP
  502.  
  503. ;=======================================
  504.  
  505. StripFile    PROC    Near
  506.  
  507. ;    Remove trailing filename, leaving just the dirname.
  508. ;    C:X            -> C:
  509. ;    C:\X.X            -> C:\
  510. ;    C:\SUB1\SUB2\X.XX   -> C:\SUB1\SUB2\
  511. ;    ^ ^        ^    ^
  512. ;    a b        c    d
  513. ;    input    DS:BX=b CX=length b..d
  514. ;    results DS:BX=b CX=length b..c    di=c
  515.  
  516.     mov    di,bx
  517.     add    di,cx
  518.     dec    di        ; point to last char of string d
  519.     std            ; scan back
  520.     mov    al,'\'
  521.     repne    scasb
  522.     cld
  523.     jne    NoSlash
  524.     inc    di
  525.     inc    cx
  526. NoSlash:
  527.     ret
  528.  
  529. StripFile    ENDP
  530.  
  531. ;=======================================
  532.  
  533. BuildFilename    Proc
  534.  
  535. ;    Tack filename from the DTA onto the end of the dirname in
  536. ;    the command line forming an ASCIIZ string.  Leave result in
  537. ;    DS:BX
  538.  
  539.     lea    si,Fname    ; source in DTA
  540.     mov    di,DirTack    ; where to tack on next char
  541.                 ; target is in the command line.
  542.                 ; we overwrite wildcard, but it is no longer
  543.                 ; needed.
  544.     mov    cx,7        ; 13=8+3+null by words
  545.     rep    movsw        ; copy over
  546.  
  547.     mov    bx,DirStart    ; DS:bx is start of full generated filename.
  548.  
  549.     ret
  550.  
  551. BuildFilename    EndP
  552.  
  553. ;=======================================
  554.  
  555.  
  556. RidRO    PROC    NEAR
  557.  
  558. ;    get rid of file whose asciiz name is in DS:BX
  559. ;    get rid of read only status and delete it.
  560.  
  561.     mov    dx,bx
  562.  
  563.     test    Fattrib,1        ; attribute of file found in DTA
  564.                     ; is it read only?
  565.     jz    PlainFile
  566.                     ; was read-only, turn that off
  567.     xor    cx,cx            ; CX=attrib
  568.     mov    ax,4301h        ; change attribute to vanilla
  569.     int    21h
  570.  
  571. Plainfile:
  572.     mov    ah,41h            ; delete it
  573.     int    21h
  574.     jc    WouldNotDie
  575.     mov    errorlevel,0        ; record success
  576. WouldNotDie:
  577.     ret
  578.  
  579. RidRO    ENDP
  580.  
  581. ;=======================================================
  582.  
  583. FindNext    Proc
  584.  
  585. ;    Find next file that matches our wildcard spec
  586. ;    we no longer need the wildcard spec
  587.  
  588.     mov    ah,4Fh
  589.     int    21h        ; find next
  590.                 ; STC notes trouble
  591.                 ; DTA contains results
  592.     ret
  593.  
  594. FindNext    EndP
  595.  
  596. ;=======================================
  597.  
  598.  
  599. CODE    ENDS
  600.     END    Start
  601.